<?php
namespace Swoole\Http;

use Swoole;

/**
 * Class ExtParser
 * 使用pecl_http扩展
 * @package Swoole\Http
 */
class Parser
{
    const HTTP_EOF = "\r\n\r\n";

    protected $buffer;

    /**
     * 头部解析
     * @param $data
     * @return array
     */
    static function parseHeader($data)
    {
        $header = array();
        $header[0] = array();
        $meta = &$header[0];
        $parts = explode("\r\n\r\n", $data, 2);


        // parts[0] = HTTP头;
        // parts[1] = HTTP主体，GET请求没有body
        // 把请求处的头部数据拿出来,针对第一行
        $headerLines = explode("\r\n", $parts[0]);

        // HTTP协议头,方法，路径，协议[RFC-2616 5.1]
        // 按规则分解头部,取出协议参数
        list($meta['method'], $meta['uri'], $meta['protocol']) = explode(' ', $headerLines[0], 3);

        //错误的HTTP请求,针对非标准的提交
        if (empty($meta['method']) or empty($meta['uri']) or empty($meta['protocol']))
        {
            return false;
        }
        unset($headerLines[0]);
        //解析Header
        $header = array_merge($header, self::parseHeaderLine($headerLines));
        return $header;
    }

    /**
     * 传入一个字符串或者数组
     * @param $headerLines string/array
     * @return array
     */
    static function parseHeaderLine($headerLines)
    {
        if (is_string($headerLines))
        {
            $headerLines = explode("\r\n", $headerLines);
        }
        $header = array();
        foreach ($headerLines as $_h)
        {
            // 去除无效的头部参数
            $_h = trim($_h);
            if (empty($_h)) continue;
            // 对正确的头部参数进行分解
            $_r = explode(':', $_h, 2);
            // 头字段名称首字母大写
            // 区分出类似User-Agent字段,把单词首字母大写
            $keys = explode('-', $_r[0]);
            $keys = array_map("ucfirst", $keys);
            $key = implode('-', $keys);
            // 判断值是否为存在
            $value = isset($_r[1])?$_r[1]:'';
            $header[trim($key)] = trim($value);
        }
        return $header;
    }

    /**
     * 解析post-from方式提交的参数
     */
    static function parseParams($str)
    {
        $params = array();
        $blocks = explode(";", $str);
        foreach ($blocks as $b)
        {
            $_r = explode("=", $b, 2);
            if(count($_r)==2)
            {
                list ($key, $value) = $_r;
                $params[trim($key)] = trim($value, "\r\n \t\"");
            }
            else
            {
                $params[$_r[0]] = '';
            }
        }
        return $params;
    }

    /**
     * 解析Body
     * @param $request Swoole\Request
     */
    function parseBody(Swoole\Request $request)
    {
        //判断是什么类型的post,涉及格式的读取问题
        if (isset($request->header['Content-Type'])) {
            $cd = strstr($request->header['Content-Type'], 'boundary');
            if (isset($request->header['Content-Type']) and $cd !== false) {
                $this->parseFormData($request, $cd);
            } else {
                if (substr($request->header['Content-Type'], 0, 33) == 'application/x-www-form-urlencoded') {
                    parse_str($request->body, $request->post);
                }
                if (substr($request->header['Content-Type'], 0, 16) == 'application/json') {
	 $request->post=json_decode($request->body,true);
                }
            }
        }
    }

    /**
     * 解析Cookies
     * @param $request Swoole\Request
     */
    function parseCookie(Swoole\Request $request)
    {
        $request->cookie = self::parseParams($request->header['Cookie']);
    }

    /**
     * 解析form_data格式文件
     * @param $part
     * @param $request Swoole\Request
     * @param $cd
     */
    static function parseFormData(Swoole\Request $request, $cd)
    {
        $cd = '--' . str_replace('boundary=', '', $cd);
        $form = explode($cd, rtrim($request->body, "-")); //去掉末尾的--
        foreach ($form as $f)
        {
            if ($f === '')
            {
                continue;
            }
            $parts = explode("\r\n\r\n", trim($f));
            $header = self::parseHeaderLine($parts[0]);
            if (!isset($header['Content-Disposition']))
            {
                continue;
            }
            $meta = self::parseParams($header['Content-Disposition']);
            //filename字段表示它是一个文件
            if (!isset($meta['filename']))
            {
                if (count($parts) < 2)
                {
                    $parts[1] = "";
                }
                //支持checkbox
                if (substr($meta['name'], -2) === '[]')
                {
                    $request->post[substr($meta['name'], 0, -2)][] = trim($parts[1]);
                }
                else
                {
                    $request->post[$meta['name']] = trim($parts[1], "\r\n");
                }
            }
            else
            {

                    
                $tmp_file = tempnam('/tmp', 'sw');
                $pathinfo = pathinfo($meta['filename']);
                if (is_array($pathinfo)) {
                        $extensions = strtolower($pathinfo['extension']);
                        $tmp_file=$tmp_file.'.'.$extensions;   
                    }
               file_put_contents($tmp_file, $parts[1]);
                if (!isset($meta['name']))
                {
                    $meta['name'] = 'file';
                }
    


                //需要加入后缀名
                $request->files[$meta['name']] = array(
                    'name' => $meta['filename'],
                    'type' => $header['Content-Type'],
                    'size' => strlen($parts[1]),
                    'error' => UPLOAD_ERR_OK,
                    //必须构造一个后缀,否则tp会视为非法文件
                    'tmp_name' =>$tmp_file,
                );
                //针对特殊情况构造
//                 $request->files['upload'] = array(
//                    'error' => 0,
//                );
//                $request->files["upload"]['error'] = 0;
            }
        }
    }

    /**
     * 头部http协议
     * @param $data
     * @return array
     */
    function parse($data)
    {
        $_header = strstr($data, self::HTTP_EOF, true);
        if ($_header === false)
        {
            $this->buffer = $data;
        }
        $header = self::parseHeader($_header);
        if ($header === false)
        {
            $this->isError = true;
        }
        $this->header = $header;
        return $header;
    }

}
